#include <cstring>
#include <ostream>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>

using namespace std;

class COWString{
public:
    COWString():_pstr(new char[5]()+4){
        InitCount();
    }

    COWString(const char *p):_pstr(new char[strlen(p)+5]()+4){
        InitCount();
        strcpy(_pstr,p);
    }

    COWString(const COWString &rhs):_pstr(rhs._pstr){
        CounterInc();
    }

    COWString & operator=(const COWString &rhs){
        if(this!=&rhs){
            if(--*(int *)(_pstr-4)==0){
                delete[] (_pstr-4);
                _pstr=rhs._pstr;
                CounterInc();
            }
        }
        return *this;

    }

    ~COWString(){
        if(getCount()==0){
            delete[] (_pstr-4);
        }
    }

    int getCount(){
        return *(int *)(_pstr-4);
    }

    void InitCount(){
        *(int *)(_pstr-4)=1;
    }

    void CounterDec(){
        --*(int *)(_pstr-4);
    }

    void CounterInc(){
       ++*(int *)(_pstr-4);
    }

    char & operator[](const size_t idx){
        if(idx>strlen(_pstr)){
            static char nullchar='\0';
            return nullchar;
        }
        if(getCount()>1){
            CounterDec();
            char *temp=new char[strlen(_pstr)+5]()+4; 
            strcpy(temp,_pstr);
            _pstr=temp;
            InitCount();
        }
        return _pstr[idx];
    }

    friend ostream& operator<<(ostream& os,COWString &rhs);

private:
    char *_pstr;
};

ostream& operator<<(ostream& os,COWString &rhs){
    os<<rhs._pstr;
    return os;
}

void test(){
    COWString s1("First");
    cout<<" -- s1: "<<s1<<"\t count:"<<s1.getCount()<<" -- "<<endl;
    
    COWString s2("First");
    cout<<" -- s2: "<<s1<<"\t count:"<<s2.getCount()<<" -- "<<endl;
    
    COWString s3(s1);
    cout<<" -- s3: "<<s1<<"\t count:"<<s3.getCount()<<" -- "<<endl;
    cout<<" -- s1: "<<s1<<"\t count:"<<s1.getCount()<<" -- "<<endl;

    s3[2]='F';
    cout<<" -- s3: "<<s3<<"\t count:"<<s3.getCount()<<" -- "<<endl;

    COWString s4=s3;
    COWString s5=s3;
    COWString s6=s3;
    cout<<" -- s3: "<<s3<<"\t count:"<<s3.getCount()<<" -- "<<endl;
    cout<<" -- s4: "<<s4<<"\t count:"<<s4.getCount()<<" -- "<<endl;
    cout<<endl;
    cout<<" --\t []存在只读影响引用计数的问题 \t--"<<endl;
    cout<<" -- s4[1]: "<<s4[1]<<"\t s3:count:"<<s3.getCount()<<" -- "<<endl;
    cout<<" -- s5[2]: "<<s5[2]<<"\t s3:count:"<<s3.getCount()<<" -- "<<endl;
    cout<<" -- s6[3]: "<<s6[3]<<"\t s3:count:"<<s3.getCount()<<" -- "<<endl;
    cout<<" -- s3: "<<s3<<"\t s3:count:"<<s3.getCount()<<" -- "<<endl;
}

int main()
{
 test();
 return 0;
}

